package com.hanxiaozhang.no10leetcode.array;

import java.util.Arrays;

/**
 * 〈一句话功能简述〉<br>
 * 〈〉
 * 给定一个n阶2维数组，你可以把它想象成一个图片。要求顺时针旋转九十度
 * 注意：类似于原地排序，本题要求原地旋转，即不能使用额外的存储空间，通过另一个二维数组来进行辅助操作。
 *
 * 思路：参考方法2
 * 分两步走：1.对角线为轴翻转得到其转置矩阵; 2.以中间竖轴翻转。
 *
 * @author hanxinghua
 * @create 2024/1/17
 * @since 1.0.0
 */
public class No48RotateImage {


    public static void main(String[] args) {

        int[][] nums1 = {
                {1, 2, 3},
                {4, 5, 6},
                {7, 8, 9}
        };

        int[][] nums2 = {
                {7, 4, 1},
                {8, 5, 2},
                {9, 6, 3}
        };

        // System.out.println(Arrays.deepToString(method1(nums1)));

        System.out.println(Arrays.deepToString(method2(nums1)));
    }




      /*
       方法1：
           旋转后  旋转前
        7: (0,0)  (2,0)
        4: (0,1) (1,0)
        1: (0,2) (0,0)

        8: (1,0) (2,1)
        5: (1,1) (1,1)
        2: (1,2) (0,1)

        ...

        推论出： 后[行][列] =前[长度 - 1 -列][行]

         */

    /**
     * 方法1
     * <p>
     * 不符合题干要求
     *
     * @param nums
     * @return
     */
    private static int[][] method1(int[][] nums) {

        // 二维数组  行 列
        int[][] result = new int[nums.length][nums.length];

        for (int i = 0; i < nums.length; i++) {
            for (int j = 0; j < nums.length; j++) {
                result[i][j] = nums[nums.length - 1 - j][i];
            }
        }
        return result;
    }



    /*
    分两步走： 1.对角线为轴翻转得到其转置矩阵; 2.以中间竖轴翻转。
    1  2  3　　　 　  1  4  7　　　　  7  4  1
    4  5  6 　-->　  2  5  8　 -->   8  5  2　　
    7  8  9 　　　   3  6  9　　   　 9  6  3

    翻转分析：
     1. 对角线为轴翻转： ->  推论出：后[行][列] =后[列][行]
     2: (0,1)  -> (1,0)
     3: (0,2)  -> (2,0)
     ...
     6: (1,2)  -> (2,1)
     ...

     2. 以中间竖轴翻转：->  推论出：后[行][列] =后[行][长度 - 1 -列]
     7: (0,0) -> (0,2)
     4: (0,1) -> (0,1)
     1: (0,2) -> (0,0)
     ...

     循环边界值分析：
     1. 对角线双层循环控制：
      - 外层循环行，除第0行，每行都循环到  -> 推论出： for(int i = 1; i < nums.length ...
      - 内层循环列， 即 for(int j = 0; j < i ...
      -- 第1行，需要处理0列
      -- 第2行，需要处理0,1列

     2. 中间竖轴双层循环控制：
     - 外层循环行，每行都循环到 -> 推论出： for(int i = 0; i <= nums.length/2 ...
     - 内层循环列，中间竖轴
     -- 列偶数个，有两个中位数，需要处理第一个中位数之前的元素（包含第一个中位数）。 nums.length/2  6/2=3  (0,1,2)
     -- 列奇数个，有一个中位数，需要处理中位数之前的元素（不包含中位数）。 但是nums.length/2  例如：7/2=3  (0,1,2) 包含中位数。
        为了覆盖偶数，奇数也可以出处理一位


     */

    /**
     * 方法2
     * <p>
     * 参考：
     * https://www.cnblogs.com/zl1991/p/9665595.html
     *
     * @param nums
     * @return
     */
    private static int[][] method2(int[][] nums) {
        for (int i = 1; i < nums.length; i++) {
            for (int j = 0; j < i; j++) {
                int temp = nums[i][j];
                nums[i][j] = nums[j][i];
                nums[j][i] = temp;
            }
        }
        for (int i = 0; i < nums.length; i++) {
            for (int j = 0; j <= nums.length / 2; j++) {
                int temp = nums[i][j];
                nums[i][j] = nums[i][nums.length - 1 - j];
                nums[i][nums.length - 1 - j] = temp;
            }
        }
        return nums;
    }


}
